package main

import (
	"fmt"
	"sync"
	"time"
)

//用map实现线程安全的集合set
/*
NewSet方法初始化
Add方法添加元素，添加重复元素可以去重
Del方法删除元素
Merge方法合并另一个set
PrintElement方法打印所有元素
JudgeElement方法检测输入的string是否存在于set中
*/

type SafeSet struct {
	sync.RWMutex
	m map[string]struct{}
}

func NewSet() *SafeSet {
	return &SafeSet{
		m: make(map[string]struct{}),
	}
}

func (ss *SafeSet) Add(key string) {
	ss.Lock()
	defer ss.Unlock()
	ss.m[key] = struct{}{}
}

func (ss *SafeSet) Del(key string) {
	ss.Lock()
	defer ss.Unlock()
	delete(ss.m, key)
}

func (ss *SafeSet) PrintElement() []string {
	ss.RLock()
	defer ss.RUnlock()
	res := make([]string, 0)
	for k := range ss.m {
		res = append(res, k)
	}
	return res
}

func (ss *SafeSet) JudgeElement(key string) bool {
	ss.RLock()
	defer ss.RUnlock()
	_, ok := ss.m[key]
	return ok
}

func (ss *SafeSet) Merge(set *SafeSet) {
	ss.Lock()
	defer ss.Unlock()
	keys := set.PrintElement()
	for _, k := range keys {
		//ss.Add(k)
		ss.m[k] = struct{}{}
	}

}

func setAdd(set *SafeSet, n int) {
	for i := 0; i < n; i++ {
		key := fmt.Sprintf("key_%d", i)
		set.Add(key)
	}
}

func setDel(set *SafeSet, n int) {
	for i := 0; i < n; i++ {
		key := fmt.Sprintf("key_%d", i)
		set.Del(key)
	}
}

func main() {
	s1 := NewSet()
	setAdd(s1, 10)
	fmt.Println(s1.PrintElement())
	setDel(s1, 5)
	fmt.Println(s1.PrintElement())

	s2 := NewSet()
	setAdd(s2, 20)
	s1.Merge(s2)
	fmt.Println(s1.PrintElement())

	go setAdd(s1, 100)
	go setDel(s1, 100)
	go setAdd(s1, 300)
	go setDel(s1, 300)
	time.Sleep(10 * time.Minute)
}
